// Copyright (c) 2022 wick.zt arg-go is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of
// the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

package arg

import (
	"strings"
)

type token string

func parseTag(tag string) (tokens []token, err error) {
	sb := &strings.Builder{}
	quote := false
	for i := 0; i < len(tag); i++ {
		r := tag[i]

		if quote && r == '>' && (i == len(tag)-1 || tag[i+1] == ',') {
			sb.WriteByte(r)
			tokens = append(tokens, token(sb.String()))
			sb.Reset()
			quote = false
			if i < len(tag)-1 && tag[i+1] == ',' {
				i++
			}
			continue
		}

		if r == '<' {
			sb.WriteByte(r)
			quote = true
			continue
		}

		if !quote && r == ',' {
			tokens = append(tokens, token(sb.String()))
			sb.Reset()
			continue
		}

		sb.WriteByte(r)
	}

	if quote {
		return nil, &ValueError{PartialToken, "partial token", tag}
	}

	if rem := sb.String(); rem != "" {
		tokens = append(tokens, token(rem))
	}
	return
}

func (t token) isShortFlag() bool {
	return len(t) == 2 && t[0] == '-' && t[1] != '-'
}

func (t token) isLongFlag() bool {
	return len(t) >= 3 && t[0] == '-' && t[1] == '-' && t[2] != '-'
}

func (t token) isUsage() bool {
	return len(t) >= 2 && t[0] == ':'
}

func (t token) isValue() bool {
	return len(t) >= 3 && t[0] == '<' && t[len(t)-1] == '>'
}

func (t token) isAttr() bool {
	return len(t) == 2 && t[0] == '+'
}

type Attr int

const (
	AttrZeroArgs  Attr = iota // +0, bool auto
	AttrOneArg                // +1, default
	AttrMultiArgs             // +n
	AttrRequired              // +r
)

func parseAttr(v byte) (Attr, error) {
	switch v {
	case 'r':
		return AttrRequired, nil
	case '0':
		return AttrZeroArgs, nil // will never be used
	case '1':
		return AttrOneArg, nil // will never be used
	case 'n':
		return AttrMultiArgs, nil // TODO: not supported yet
	}
	return -1, &ValueError{UnknownAttribute, "unknown attribute", v}
}
